import logging
from datetime import datetime, timedelta, time
from decimal import Decimal
from django.utils import timezone
from django.db import transaction
from django.core.exceptions import ValidationError
from django.db.models import Q

from app.models import Employee, Attendance, EmployeeActivity, LeaveRequest, PerformanceRecord
from middleware.util import make_response

logger = logging.getLogger(__name__)


class DailySettlementService:
    """每日自动结算服务"""

    @staticmethod
    def auto_settle_all_employees(settlement_date=None):
        """
        自动结算所有员工的每日绩效
        :param settlement_date: 结算日期，默认为昨天
        :return: 结算结果统计
        """
        if settlement_date is None:
            # 默认结算昨天的数据
            settlement_date = (timezone.now() - timedelta(days=1)).date()

        logger.info(f"开始执行每日自动结算，结算日期：{settlement_date}")

        success_count = 0
        error_count = 0
        error_details = []

        try:
            # 获取所有在职员工
            active_employees = Employee.objects.filter(employment_status='active')
            total_employees = active_employees.count()

            logger.info(f"需要结算的员工总数：{total_employees}")

            for employee in active_employees:
                try:
                    # 为每个员工计算当日绩效
                    result = DailySettlementService._calculate_employee_daily_performance(
                        employee, settlement_date
                    )
                    if result['success']:
                        success_count += 1
                        logger.debug(f"员工 {employee.real_name} 结算成功")
                    else:
                        error_count += 1
                        error_details.append({
                            'user_id': str(employee.user_id),  # 修改：原来是employee_id
                            'employee_name': employee.real_name,
                            'error': result['error']
                        })
                        logger.warning(f"员工 {employee.real_name} 结算失败：{result['error']}")

                except Exception as e:
                    error_count += 1
                    error_msg = f"结算异常：{str(e)}"
                    error_details.append({
                        'user_id': str(employee.user_id),  # 修改：原来是employee_id
                        'employee_name': employee.real_name,
                        'error': error_msg
                    })
                    logger.error(f"员工 {employee.real_name} 结算异常：{str(e)}", exc_info=True)

            # 记录结算统计日志
            logger.info(f"每日自动结算完成 - 成功：{success_count}，失败：{error_count}")

            return {
                'success': True,
                'settlement_date': settlement_date.isoformat(),
                'total_employees': total_employees,
                'success_count': success_count,
                'error_count': error_count,
                'error_details': error_details
            }

        except Exception as e:
            logger.error(f"每日自动结算过程中发生严重错误：{str(e)}", exc_info=True)
            return {
                'success': False,
                'error': str(e),
                'settlement_date': settlement_date.isoformat() if settlement_date else None
            }

    @staticmethod
    def _calculate_employee_daily_performance(employee, record_date):
        """
        计算单个员工的每日绩效
        :param employee: 员工对象
        :param record_date: 记录日期
        :return: 计算结果
        """
        try:
            with transaction.atomic():
                # 检查是否已经结算过（防止重复结算）
                existing_record = PerformanceRecord.objects.filter(
                    employee=employee,
                    record_date=record_date
                ).first()

                if existing_record:
                    logger.debug(f"员工 {employee.real_name} 在 {record_date} 已有绩效记录，跳过结算")
                    return {'success': True, 'message': '已存在绩效记录，跳过'}

                # 检查是否应该上班
                weekday = record_date.weekday()
                work_days = [
                    employee.monday_work, employee.tuesday_work, employee.wednesday_work,
                    employee.thursday_work, employee.friday_work, employee.saturday_work, employee.sunday_work
                ]
                is_work_day = work_days[weekday]

                # 获取考勤记录
                try:
                    attendance = Attendance.objects.get(employee=employee, work_date=record_date)
                except Attendance.DoesNotExist:
                    attendance = None

                # 检查请假状态
                is_on_leave = LeaveRequest.objects.filter(
                    employee=employee,
                    status='approved',
                    start_date__lte=record_date,
                    end_date__gte=record_date
                ).exists()

                is_present = bool(attendance and attendance.actual_start is not None and attendance.actual_end is not None)

                # 计算考勤时间
                late_minutes = 0
                early_leave_minutes = 0
                overtime_minutes = 0
                work_minutes = 0

                if attendance and attendance.actual_start is not None and attendance.actual_end is not None:
                    # 计算迟到时间
                    if attendance.actual_start > attendance.scheduled_start:
                        late_delta = datetime.combine(record_date, attendance.actual_start) - \
                                     datetime.combine(record_date, attendance.scheduled_start)
                        late_minutes = int(late_delta.total_seconds() / 60)

                    # 计算早退时间
                    if attendance.actual_end < attendance.scheduled_end:
                        early_delta = datetime.combine(record_date, attendance.scheduled_end) - \
                                      datetime.combine(record_date, attendance.actual_end)
                        early_leave_minutes = int(early_delta.total_seconds() / 60)

                    # 计算加班时间
                    if attendance.actual_end > attendance.scheduled_end:
                        overtime_delta = datetime.combine(record_date, attendance.actual_end) - \
                                         datetime.combine(record_date, attendance.scheduled_end)
                        overtime_minutes = int(overtime_delta.total_seconds() / 60)

                    # 计算实际工作时间
                    work_delta = datetime.combine(record_date, attendance.actual_end) - \
                                 datetime.combine(record_date, attendance.actual_start)
                    work_minutes = int(work_delta.total_seconds() / 60)

                # 获取当日活动次数
                activity_count = EmployeeActivity.objects.filter(
                    employee=employee,
                    activity_time__date=record_date
                ).count()

                # 计算工资
                base_salary = employee.base_daily_salary if (is_work_day and (is_present or is_on_leave)) else Decimal('0')
                late_penalty = Decimal(str(late_minutes)) * employee.late_penalty_per_minute
                early_leave_penalty = Decimal(str(early_leave_minutes)) * employee.early_leave_penalty_per_minute
                activity_bonus = Decimal(str(activity_count)) * employee.activity_bonus_per_count
                overtime_bonus = (Decimal(str(overtime_minutes)) / Decimal('60')) * (employee.base_daily_salary / Decimal('8'))  # 按小时计算加班费

                daily_total_salary = base_salary - late_penalty - early_leave_penalty + activity_bonus + overtime_bonus

                # 创建绩效记录
                performance = PerformanceRecord.objects.create(
                    employee=employee,
                    record_date=record_date,
                    is_work_day=is_work_day,
                    is_present=is_present,
                    is_on_leave=is_on_leave,
                    late_minutes=late_minutes,
                    early_leave_minutes=early_leave_minutes,
                    overtime_minutes=overtime_minutes,
                    work_minutes=work_minutes,
                    activity_count=activity_count,
                    base_salary=base_salary,
                    late_penalty=late_penalty,
                    early_leave_penalty=early_leave_penalty,
                    activity_bonus=activity_bonus,
                    overtime_bonus=overtime_bonus,
                    daily_total_salary=daily_total_salary,
                )

                logger.debug(f"员工 {employee.real_name} 每日绩效计算完成，总工资：{daily_total_salary}")

                return {
                    'success': True,
                    'performance_id': str(performance.performance_id),
                    'daily_total_salary': float(daily_total_salary),
                    'is_present': bool(is_present),
                    'is_on_leave': bool(is_on_leave),
                    'activity_count': activity_count
                }

        except Exception as e:
            logger.error(f"员工 {employee.real_name} 绩效计算失败：{str(e)}", exc_info=True)
            return {'success': False, 'error': str(e)}

    @staticmethod
    def settle_specific_employee(user_id, settlement_date=None):
        """
        结算指定员工的绩效（用于手动补结算）
        :param user_id: 用户ID (修改：原来是employee_id)
        :param settlement_date: 结算日期，默认为昨天
        :return: 结算结果
        """
        if settlement_date is None:
            settlement_date = (timezone.now() - timedelta(days=1)).date()

        try:
            employee = Employee.objects.get(user_id=user_id, employment_status='active')  # 修改：原来是employee_id
            result = DailySettlementService._calculate_employee_daily_performance(employee, settlement_date)

            if result['success']:
                return make_response(
                    code=200,
                    message="员工绩效结算成功",
                    data={
                        "employee_name": employee.real_name,
                        "settlement_date": settlement_date.isoformat(),
                        **result
                    }
                )
            else:
                return make_response(
                    code=400,
                    message=f"员工绩效结算失败：{result['error']}",
                    data={"employee_name": employee.real_name}
                )

        except Employee.DoesNotExist:
            raise ValidationError("员工不存在或已离职")
        except Exception as e:
            raise ValidationError(f"结算失败：{str(e)}")

    @staticmethod
    def get_settlement_statistics(start_date, end_date):
        """
        获取指定时间段的结算统计信息
        :param start_date: 开始日期
        :param end_date: 结束日期
        :return: 统计信息
        """
        try:
            # 获取时间段内的绩效记录
            performance_records = PerformanceRecord.objects.filter(
                record_date__gte=start_date,
                record_date__lte=end_date
            ).select_related('employee')

            # 统计信息
            total_records = performance_records.count()
            total_salary = sum(record.daily_total_salary for record in performance_records)

            # 按日期分组统计
            daily_stats = {}
            for record in performance_records:
                date_str = record.record_date.isoformat()
                if date_str not in daily_stats:
                    daily_stats[date_str] = {
                        'date': date_str,
                        'employee_count': 0,
                        'total_salary': 0,
                        'present_count': 0,
                        'leave_count': 0,
                        'absent_count': 0
                    }

                daily_stats[date_str]['employee_count'] += 1
                daily_stats[date_str]['total_salary'] += float(record.daily_total_salary)

                if record.is_present:
                    daily_stats[date_str]['present_count'] += 1
                elif record.is_on_leave:
                    daily_stats[date_str]['leave_count'] += 1
                else:
                    daily_stats[date_str]['absent_count'] += 1

            return make_response(
                code=200,
                message="统计信息获取成功",
                data={
                    "start_date": start_date.isoformat(),
                    "end_date": end_date.isoformat(),
                    "total_records": total_records,
                    "total_salary": float(total_salary),
                    "daily_statistics": list(daily_stats.values())
                }
            )

        except Exception as e:
            raise ValidationError(f"获取统计信息失败：{str(e)}")